//################################################################################
// MIT License
// Copyright (c) 2024 ZhangYihua
//
// Change Logs:
// Date           Author       Notes
// 2023-07-22     ZhangYihua   first version
//
// Description  : add slicer between AXI master and slave for better timing
//################################################################################

module axi_slicer #(
parameter [4:0]     REG_ON                  = 5'b11111,     // each bit for one of {b, r, ar, w, aw}
parameter           ADDR_BW                 = 16,
parameter           DATA_BW                 = 32
) ( 
input                                       rst_n,
input                                       clk,

// one AXI-lite slave(from source master)
input               [ADDR_BW-1:0]           slv_awaddr,
input                                       slv_awvalid,
output                                      slv_awready,

input               [DATA_BW-1:0]           slv_wdata,
input                                       slv_wvalid,
output                                      slv_wready,

output              [2-1:0]                 slv_bresp,
output                                      slv_bvalid,
input                                       slv_bready,

input               [ADDR_BW-1:0]           slv_araddr,
input                                       slv_arvalid,
output                                      slv_arready,

output              [DATA_BW-1:0]           slv_rdata,
output              [2-1:0]                 slv_rresp,
output                                      slv_rvalid,
input                                       slv_rready,

// one AXI-lite master(to destination slave)
output              [ADDR_BW-1:0]           mst_awaddr,
output                                      mst_awvalid,
input                                       mst_awready,

output              [DATA_BW-1:0]           mst_wdata,
output                                      mst_wvalid,
input                                       mst_wready,

input               [2-1:0]                 mst_bresp,
input                                       mst_bvalid,
output                                      mst_bready,

output              [ADDR_BW-1:0]           mst_araddr,
output                                      mst_arvalid,
input                                       mst_arready,

input               [DATA_BW-1:0]           mst_rdata,
input               [2-1:0]                 mst_rresp,
input                                       mst_rvalid,
output                                      mst_rready
);

//################################################################################
// define local varialbe and localparam
//################################################################################

//################################################################################
// main
//################################################################################

generate if (REG_ON[0]==1'b1) begin:G_AW_REG
    reg_slicer #(
            .RS_MODE                        ("BID_RS_HALF_RATE"             ),	// timing optimization for all input, but half rate pipeline
            .DAT_BW                         (ADDR_BW                        )
    ) u_slv_aw ( 
            .rst_n                          (rst_n                          ),
            .clk                            (clk                            ),

            .src_vld                        (slv_awvalid                    ),
            .src_dat                        (slv_awaddr                     ),
            .src_rdy                        (slv_awready                    ),

            .dst_vld                        (mst_awvalid                    ),
            .dst_dat                        (mst_awaddr                     ),
            .dst_rdy                        (mst_awready                    )
    );
end else begin:G_AW_NREG
    assign mst_awaddr   = slv_awaddr ;
    assign mst_awvalid  = slv_awvalid;
    assign slv_awready  = mst_awready;
end endgenerate

generate if (REG_ON[1]==1'b1) begin:G_W_REG
    reg_slicer #(
            .RS_MODE                        ("BID_RS_HALF_RATE"             ),	// timing optimization for all input, but half rate pipeline
            .DAT_BW                         (DATA_BW                        )
    ) u_slv_w ( 
            .rst_n                          (rst_n                          ),
            .clk                            (clk                            ),

            .src_vld                        (slv_wvalid                     ),
            .src_dat                        (slv_wdata                      ),
            .src_rdy                        (slv_wready                     ),

            .dst_vld                        (mst_wvalid                     ),
            .dst_dat                        (mst_wdata                      ),
            .dst_rdy                        (mst_wready                     )
    );
end else begin:G_W_NREG
    assign mst_wdata    = slv_wdata  ;
    assign mst_wvalid   = slv_wvalid ;
    assign slv_wready   = mst_wready ;
end endgenerate

generate if (REG_ON[2]==1'b1) begin:G_AR_REG
    reg_slicer #(
            .RS_MODE                        ("BID_RS_HALF_RATE"             ),	// timing optimization for all input, but half rate pipeline
            .DAT_BW                         (ADDR_BW                        )
    ) u_slv_ar ( 
            .rst_n                          (rst_n                          ),
            .clk                            (clk                            ),

            .src_vld                        (slv_arvalid                    ),
            .src_dat                        (slv_araddr                     ),
            .src_rdy                        (slv_arready                    ),

            .dst_vld                        (mst_arvalid                    ),
            .dst_dat                        (mst_araddr                     ),
            .dst_rdy                        (mst_arready                    )
    );
end else begin:G_AR_NREG
    assign mst_araddr   = slv_araddr ;
    assign mst_arvalid  = slv_arvalid;
    assign slv_arready  = mst_arready;
end endgenerate

generate if (REG_ON[3]==1'b1) begin:G_R_REG
    reg_slicer #(
            .RS_MODE                        ("BID_RS_HALF_RATE"             ),	// timing optimization for all input, but half rate pipeline
            .DAT_BW                         (DATA_BW+2                      )
    ) u_slv_r ( 
            .rst_n                          (rst_n                          ),
            .clk                            (clk                            ),

            .src_vld                        (mst_rvalid                     ),
            .src_dat                        ({mst_rdata, mst_rresp}         ),
            .src_rdy                        (mst_rready                     ),

            .dst_vld                        (slv_rvalid                     ),
            .dst_dat                        ({slv_rdata, slv_rresp}         ),
            .dst_rdy                        (slv_rready                     )
    );
end else begin:G_R_NREG
    assign slv_rdata    = mst_rdata  ;
    assign slv_rresp    = mst_rresp  ;
    assign slv_rvalid   = mst_rvalid ;
    assign mst_rready   = slv_rready ;
end endgenerate

generate if (REG_ON[4]==1'b1) begin:G_B_REG
    reg_slicer #(
            .RS_MODE                        ("BID_RS_HALF_RATE"             ),	// timing optimization for all input, but half rate pipeline
            .DAT_BW                         (2                              )
    ) u_slv_b ( 
            .rst_n                          (rst_n                          ),
            .clk                            (clk                            ),

            .src_vld                        (mst_bvalid                     ),
            .src_dat                        (mst_bresp                      ),
            .src_rdy                        (mst_bready                     ),

            .dst_vld                        (slv_bvalid                     ),
            .dst_dat                        (slv_bresp                      ),
            .dst_rdy                        (slv_bready                     )
    );
end else begin:G_B_NREG
    assign slv_bresp    = mst_bresp  ;
    assign slv_bvalid   = mst_bvalid ;
    assign mst_bready   = slv_bready ;
end endgenerate
    
//################################################################################
// ASSERTION
//################################################################################

`ifdef CBB_ASSERT_ON
// synopsys translate_off


// synopsys translate_on
`endif

endmodule
